home *** CD-ROM | disk | FTP | other *** search
/ PC go! 2017 October / PCgo 10-2017 CD-ROM Germany.iso / nw.pak / Unnamed File 004876.txt < prev    next >
Encoding:
Text File  |  2015-07-29  |  12.8 KB  |  357 lines

  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4.  
  5. define("mojo/public/js/validator", [
  6.   "mojo/public/js/codec",
  7. ], function(codec) {
  8.  
  9.   var validationError = {
  10.     NONE: 'VALIDATION_ERROR_NONE',
  11.     MISALIGNED_OBJECT: 'VALIDATION_ERROR_MISALIGNED_OBJECT',
  12.     ILLEGAL_MEMORY_RANGE: 'VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE',
  13.     UNEXPECTED_STRUCT_HEADER: 'VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER',
  14.     UNEXPECTED_ARRAY_HEADER: 'VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER',
  15.     ILLEGAL_HANDLE: 'VALIDATION_ERROR_ILLEGAL_HANDLE',
  16.     UNEXPECTED_INVALID_HANDLE: 'VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE',
  17.     ILLEGAL_POINTER: 'VALIDATION_ERROR_ILLEGAL_POINTER',
  18.     UNEXPECTED_NULL_POINTER: 'VALIDATION_ERROR_UNEXPECTED_NULL_POINTER',
  19.     MESSAGE_HEADER_INVALID_FLAG_COMBINATION:
  20.         'VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAG_COMBINATION',
  21.     MESSAGE_HEADER_MISSING_REQUEST_ID:
  22.         'VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID',
  23.     DIFFERENT_SIZED_ARRAYS_IN_MAP:
  24.         'VALIDATION_ERROR_DIFFERENT_SIZED_ARRAYS_IN_MAP',
  25.   };
  26.  
  27.   var NULL_MOJO_POINTER = "NULL_MOJO_POINTER";
  28.  
  29.   function isStringClass(cls) {
  30.     return cls === codec.String || cls === codec.NullableString;
  31.   }
  32.  
  33.   function isHandleClass(cls) {
  34.     return cls === codec.Handle || cls === codec.NullableHandle;
  35.   }
  36.  
  37.   function isNullable(type) {
  38.     return type === codec.NullableString || type === codec.NullableHandle ||
  39.         type instanceof codec.NullableArrayOf ||
  40.         type instanceof codec.NullablePointerTo;
  41.   }
  42.  
  43.   function Validator(message) {
  44.     this.message = message;
  45.     this.offset = 0;
  46.     this.handleIndex = 0;
  47.   }
  48.  
  49.   Object.defineProperty(Validator.prototype, "offsetLimit", {
  50.     get: function() { return this.message.buffer.byteLength; }
  51.   });
  52.  
  53.   Object.defineProperty(Validator.prototype, "handleIndexLimit", {
  54.     get: function() { return this.message.handles.length; }
  55.   });
  56.  
  57.   // True if we can safely allocate a block of bytes from start to
  58.   // to start + numBytes.
  59.   Validator.prototype.isValidRange = function(start, numBytes) {
  60.     // Only positive JavaScript integers that are less than 2^53
  61.     // (Number.MAX_SAFE_INTEGER) can be represented exactly.
  62.     if (start < this.offset || numBytes <= 0 ||
  63.         !Number.isSafeInteger(start) ||
  64.         !Number.isSafeInteger(numBytes))
  65.       return false;
  66.  
  67.     var newOffset = start + numBytes;
  68.     if (!Number.isSafeInteger(newOffset) || newOffset > this.offsetLimit)
  69.       return false;
  70.  
  71.     return true;
  72.   }
  73.  
  74.   Validator.prototype.claimRange = function(start, numBytes) {
  75.     if (this.isValidRange(start, numBytes)) {
  76.       this.offset = start + numBytes;
  77.       return true;
  78.     }
  79.     return false;
  80.   }
  81.  
  82.   Validator.prototype.claimHandle = function(index) {
  83.     if (index === codec.kEncodedInvalidHandleValue)
  84.       return true;
  85.  
  86.     if (index < this.handleIndex || index >= this.handleIndexLimit)
  87.       return false;
  88.  
  89.     // This is safe because handle indices are uint32.
  90.     this.handleIndex = index + 1;
  91.     return true;
  92.   }
  93.  
  94.   Validator.prototype.validateHandle = function(offset, nullable) {
  95.     var index = this.message.buffer.getUint32(offset);
  96.  
  97.     if (index === codec.kEncodedInvalidHandleValue)
  98.       return nullable ?
  99.           validationError.NONE : validationError.UNEXPECTED_INVALID_HANDLE;
  100.  
  101.     if (!this.claimHandle(index))
  102.       return validationError.ILLEGAL_HANDLE;
  103.     return validationError.NONE;
  104.   }
  105.  
  106.   Validator.prototype.validateStructHeader =
  107.       function(offset, minNumBytes, minNumFields) {
  108.     if (!codec.isAligned(offset))
  109.       return validationError.MISALIGNED_OBJECT;
  110.  
  111.     if (!this.isValidRange(offset, codec.kStructHeaderSize))
  112.       return validationError.ILLEGAL_MEMORY_RANGE;
  113.  
  114.     var numBytes = this.message.buffer.getUint32(offset);
  115.     var numFields = this.message.buffer.getUint32(offset + 4);
  116.  
  117.     if (numBytes < minNumBytes || numFields < minNumFields)
  118.       return validationError.UNEXPECTED_STRUCT_HEADER;
  119.  
  120.     if (!this.claimRange(offset, numBytes))
  121.       return validationError.ILLEGAL_MEMORY_RANGE;
  122.  
  123.     return validationError.NONE;
  124.   }
  125.  
  126.   Validator.prototype.validateMessageHeader = function() {
  127.     var err = this.validateStructHeader(0, codec.kMessageHeaderSize, 2);
  128.     if (err != validationError.NONE)
  129.       return err;
  130.  
  131.     var numBytes = this.message.getHeaderNumBytes();
  132.     var numFields = this.message.getHeaderNumFields();
  133.  
  134.     var validNumFieldsAndNumBytes =
  135.         (numFields == 2 && numBytes == codec.kMessageHeaderSize) ||
  136.         (numFields == 3 &&
  137.          numBytes == codec.kMessageWithRequestIDHeaderSize) ||
  138.         (numFields > 3 &&
  139.          numBytes >= codec.kMessageWithRequestIDHeaderSize);
  140.     if (!validNumFieldsAndNumBytes)
  141.       return validationError.UNEXPECTED_STRUCT_HEADER;
  142.  
  143.     var expectsResponse = this.message.expectsResponse();
  144.     var isResponse = this.message.isResponse();
  145.  
  146.     if (numFields == 2 && (expectsResponse || isResponse))
  147.       return validationError.MESSAGE_HEADER_MISSING_REQUEST_ID;
  148.  
  149.     if (isResponse && expectsResponse)
  150.       return validationError.MESSAGE_HEADER_INVALID_FLAG_COMBINATION;
  151.  
  152.     return validationError.NONE;
  153.   }
  154.  
  155.   // Returns the message.buffer relative offset this pointer "points to",
  156.   // NULL_MOJO_POINTER if the pointer represents a null, or JS null if the
  157.   // pointer's value is not valid.
  158.   Validator.prototype.decodePointer = function(offset) {
  159.     var pointerValue = this.message.buffer.getUint64(offset);
  160.     if (pointerValue === 0)
  161.       return NULL_MOJO_POINTER;
  162.     var bufferOffset = offset + pointerValue;
  163.     return Number.isSafeInteger(bufferOffset) ? bufferOffset : null;
  164.   }
  165.  
  166.   Validator.prototype.validateArrayPointer = function(
  167.       offset, elementSize, elementType, nullable, expectedDimensionSizes,
  168.       currentDimension) {
  169.     var arrayOffset = this.decodePointer(offset);
  170.     if (arrayOffset === null)
  171.       return validationError.ILLEGAL_POINTER;
  172.  
  173.     if (arrayOffset === NULL_MOJO_POINTER)
  174.       return nullable ?
  175.           validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;
  176.  
  177.     return this.validateArray(arrayOffset, elementSize, elementType,
  178.                               expectedDimensionSizes, currentDimension);
  179.   }
  180.  
  181.   Validator.prototype.validateStructPointer = function(
  182.       offset, structClass, nullable) {
  183.     var structOffset = this.decodePointer(offset);
  184.     if (structOffset === null)
  185.       return validationError.ILLEGAL_POINTER;
  186.  
  187.     if (structOffset === NULL_MOJO_POINTER)
  188.       return nullable ?
  189.           validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;
  190.  
  191.     return structClass.validate(this, structOffset);
  192.   }
  193.  
  194.   // This method assumes that the array at arrayPointerOffset has
  195.   // been validated.
  196.  
  197.   Validator.prototype.arrayLength = function(arrayPointerOffset) {
  198.     var arrayOffset = this.decodePointer(arrayPointerOffset);
  199.     return this.message.buffer.getUint32(arrayOffset + 4);
  200.   }
  201.  
  202.   Validator.prototype.validateMapPointer = function(
  203.       offset, mapIsNullable, keyClass, valueClass, valueIsNullable) {
  204.     // Validate the implicit map struct:
  205.     // struct {array<keyClass> keys; array<valueClass> values};
  206.     var structOffset = this.decodePointer(offset);
  207.     if (structOffset === null)
  208.       return validationError.ILLEGAL_POINTER;
  209.  
  210.     if (structOffset === NULL_MOJO_POINTER)
  211.       return mapIsNullable ?
  212.           validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;
  213.  
  214.     var mapEncodedSize = codec.kStructHeaderSize + codec.kMapStructPayloadSize;
  215.     var err = this.validateStructHeader(structOffset, mapEncodedSize, 2);
  216.     if (err !== validationError.NONE)
  217.         return err;
  218.  
  219.     // Validate the keys array.
  220.     var keysArrayPointerOffset = structOffset + codec.kStructHeaderSize;
  221.     err = this.validateArrayPointer(
  222.         keysArrayPointerOffset, keyClass.encodedSize, keyClass, false, [0], 0);
  223.     if (err !== validationError.NONE)
  224.         return err;
  225.  
  226.     // Validate the values array.
  227.     var valuesArrayPointerOffset = keysArrayPointerOffset + 8;
  228.     var valuesArrayDimensions = [0]; // Validate the actual length below.
  229.     if (valueClass instanceof codec.ArrayOf)
  230.       valuesArrayDimensions =
  231.           valuesArrayDimensions.concat(valueClass.dimensions());
  232.     var err = this.validateArrayPointer(valuesArrayPointerOffset,
  233.                                         valueClass.encodedSize,
  234.                                         valueClass,
  235.                                         valueIsNullable,
  236.                                         valuesArrayDimensions,
  237.                                         0);
  238.     if (err !== validationError.NONE)
  239.         return err;
  240.  
  241.     // Validate the lengths of the keys and values arrays.
  242.     var keysArrayLength = this.arrayLength(keysArrayPointerOffset);
  243.     var valuesArrayLength = this.arrayLength(valuesArrayPointerOffset);
  244.     if (keysArrayLength != valuesArrayLength)
  245.       return validationError.DIFFERENT_SIZED_ARRAYS_IN_MAP;
  246.  
  247.     return validationError.NONE;
  248.   }
  249.  
  250.   Validator.prototype.validateStringPointer = function(offset, nullable) {
  251.     return this.validateArrayPointer(
  252.         offset, codec.Uint8.encodedSize, codec.Uint8, nullable, [0], 0);
  253.   }
  254.  
  255.   // Similar to Array_Data<T>::Validate()
  256.   // mojo/public/cpp/bindings/lib/array_internal.h
  257.  
  258.   Validator.prototype.validateArray =
  259.       function (offset, elementSize, elementType, expectedDimensionSizes,
  260.                 currentDimension) {
  261.     if (!codec.isAligned(offset))
  262.       return validationError.MISALIGNED_OBJECT;
  263.  
  264.     if (!this.isValidRange(offset, codec.kArrayHeaderSize))
  265.       return validationError.ILLEGAL_MEMORY_RANGE;
  266.  
  267.     var numBytes = this.message.buffer.getUint32(offset);
  268.     var numElements = this.message.buffer.getUint32(offset + 4);
  269.  
  270.     // Note: this computation is "safe" because elementSize <= 8 and
  271.     // numElements is a uint32.
  272.     var elementsTotalSize = (elementType === codec.PackedBool) ?
  273.         Math.ceil(numElements / 8) : (elementSize * numElements);
  274.  
  275.     if (numBytes < codec.kArrayHeaderSize + elementsTotalSize)
  276.       return validationError.UNEXPECTED_ARRAY_HEADER;
  277.  
  278.     if (expectedDimensionSizes[currentDimension] != 0 &&
  279.         numElements != expectedDimensionSizes[currentDimension]) {
  280.       return validationError.UNEXPECTED_ARRAY_HEADER;
  281.     }
  282.  
  283.     if (!this.claimRange(offset, numBytes))
  284.       return validationError.ILLEGAL_MEMORY_RANGE;
  285.  
  286.     // Validate the array's elements if they are pointers or handles.
  287.  
  288.     var elementsOffset = offset + codec.kArrayHeaderSize;
  289.     var nullable = isNullable(elementType);
  290.  
  291.     if (isHandleClass(elementType))
  292.       return this.validateHandleElements(elementsOffset, numElements, nullable);
  293.     if (isStringClass(elementType))
  294.       return this.validateArrayElements(
  295.           elementsOffset, numElements, codec.Uint8, nullable, [0], 0);
  296.     if (elementType instanceof codec.PointerTo)
  297.       return this.validateStructElements(
  298.           elementsOffset, numElements, elementType.cls, nullable);
  299.     if (elementType instanceof codec.ArrayOf)
  300.       return this.validateArrayElements(
  301.           elementsOffset, numElements, elementType.cls, nullable,
  302.           expectedDimensionSizes, currentDimension + 1);
  303.  
  304.     return validationError.NONE;
  305.   }
  306.  
  307.   // Note: the |offset + i * elementSize| computation in the validateFooElements
  308.   // methods below is "safe" because elementSize <= 8, offset and
  309.   // numElements are uint32, and 0 <= i < numElements.
  310.  
  311.   Validator.prototype.validateHandleElements =
  312.       function(offset, numElements, nullable) {
  313.     var elementSize = codec.Handle.encodedSize;
  314.     for (var i = 0; i < numElements; i++) {
  315.       var elementOffset = offset + i * elementSize;
  316.       var err = this.validateHandle(elementOffset, nullable);
  317.       if (err != validationError.NONE)
  318.         return err;
  319.     }
  320.     return validationError.NONE;
  321.   }
  322.  
  323.   // The elementClass parameter is the element type of the element arrays.
  324.   Validator.prototype.validateArrayElements =
  325.       function(offset, numElements, elementClass, nullable,
  326.                expectedDimensionSizes, currentDimension) {
  327.     var elementSize = codec.PointerTo.prototype.encodedSize;
  328.     for (var i = 0; i < numElements; i++) {
  329.       var elementOffset = offset + i * elementSize;
  330.       var err = this.validateArrayPointer(
  331.           elementOffset, elementClass.encodedSize, elementClass, nullable,
  332.           expectedDimensionSizes, currentDimension);
  333.       if (err != validationError.NONE)
  334.         return err;
  335.     }
  336.     return validationError.NONE;
  337.   }
  338.  
  339.   Validator.prototype.validateStructElements =
  340.       function(offset, numElements, structClass, nullable) {
  341.     var elementSize = codec.PointerTo.prototype.encodedSize;
  342.     for (var i = 0; i < numElements; i++) {
  343.       var elementOffset = offset + i * elementSize;
  344.       var err =
  345.           this.validateStructPointer(elementOffset, structClass, nullable);
  346.       if (err != validationError.NONE)
  347.         return err;
  348.     }
  349.     return validationError.NONE;
  350.   }
  351.  
  352.   var exports = {};
  353.   exports.validationError = validationError;
  354.   exports.Validator = Validator;
  355.   return exports;
  356. });
  357.